#include "modbus_master.h"
#include <iostream>
#include <sstream>
#include "log/syslog.h"

#define TAG "ModbusMaster"

using namespace equip_system;
extern system_log::CSysLog syslog;

ModbusMaster::ModbusMaster()
    : port(502), ip("192.168.1.100"), is_connected(false), ctx(nullptr), callback_data(nullptr), callback_parent(nullptr){

                                                                                                 };
/*
    构造
    _id : IP地址
    _port : 端口号
    _callback_data : 回调函数
    _callback_parent : 回调函数父指针
*/
ModbusMaster::ModbusMaster(const string &_ip, int _port, LPGETDATA _callback_data, LPVOID _parent)
    : port(_port), ip(_ip), is_connected(false), ctx(nullptr), callback_data(_callback_data), callback_parent(_parent){

                                                                                              };
ModbusMaster::~ModbusMaster()
{
    Stop();
    if (ctx)
    {
        modbus_close(ctx);
        modbus_free(ctx);
        ctx = nullptr;
    }

    callback_data = nullptr;
    callback_parent = nullptr;
};
bool ModbusMaster::Start(/*int modbusPort */)
{
    if (is_connected)
        return true;

    // 1. 创建Modbus TCP上下文
    ctx = modbus_new_tcp(ip.c_str(), port);
    if (ctx == nullptr)
    {
        // std::cerr << "Failed to create Modbus context!" << std::endl;
        string _infor("Failed to create Modbus-Node context!");
        ES_LOG(TAG, LEVEL_ERROR, _infor.c_str());
        // syslog.print(_infor.c_str());
        return false;
    }

#ifdef EQUIP_DEBUG
    modbus_set_debug(ctx, TRUE);
#endif

    modbus_set_slave(ctx, 1); //设定从站ID，范围1~247(0x01~0xF)

    // 2. 设置超时时间（1秒）
    if (modbus_set_response_timeout(ctx, 1, 0) == -1)
    {
        // std::cerr << "Modbus设置超时失败 (" << modbus_strerror(errno) << ")" << std::endl;
        // fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
        string _infor("Failed to setting Modbus-Node timeout!");
        ES_LOG(TAG, LEVEL_ERROR, _infor.c_str());
        // syslog.print(_infor.c_str());
        modbus_free(ctx);
        ctx = nullptr;
        return false;
    }

    string _infor("Modbus-Node starting is success!");
    ES_LOG(TAG, LEVEL_INFO, _infor.c_str());
    // syslog.print(_infor.c_str());

    return true;
}

bool ModbusMaster::Run()
{
    // 检查连接状态
    if (ctx == nullptr)
    {
        string _infor = "Modbus-Node not connected, unable to read register!";
        ES_LOG(TAG, LEVEL_ERROR, _infor.c_str());
        // syslog.print(_infor.c_str());
        return false;
    }

    // 3. 连接到Modbus从站
    if (modbus_connect(ctx) == -1)
    {
        // std::cerr << "Modbus connection failed: " << modbus_strerror(errno) << std::endl;
        char _infor[256] = {"Modbus-Node connection failed:"};
        sprintf(_infor, "Modbus-Node connection failed: %s", modbus_strerror(errno));
        // string _infor("Modbus connection failed:");
        ES_LOG(TAG, LEVEL_ERROR, _infor);
        modbus_free(ctx);
        ctx = nullptr;
        return false;
    }

    is_connected = true;

    string _infor("Modbus-Node connect is success!");
    ES_LOG(TAG, LEVEL_INFO, _infor.c_str());
    // syslog.print(_infor.c_str());
    return true;
}

void ModbusMaster::Stop()
{
    if (!is_connected)
        return;

    is_connected = false;
    if (thread_.joinable())
    {
        thread_.join();
    }
}

int ModbusMaster::readData(NodeData_Config &data)
{
    // 检查连接状态
    if (!is_connected || ctx == nullptr)
    {
        string _infor = "Modbus-Node not connected, unable to read register!";
        ES_LOG(TAG, LEVEL_ERROR, _infor.c_str());
        return -1;
    }

    return _read_FUN_Code(data.list);
}
/**
 * 将 uint16_t 数值转换为对应的 ASCII 字符串
 * @param value 待转换的 16 位无符号整数
 * @return 由两个 ASCII 字符组成的字符串（若字节对应非打印字符，仍会转换）
 */
string ModbusMaster::_ASCII2String(const uint16_t value)
{
    string _out;

    // 提取高8位（第1个字节），转换为 ASCII 字符
    uint8_t h = (value >> 8) & 0xFF;  // 右移8位并掩码，获取高8位
    if (h != 0)                       // 只添加非空字符
        _out += static_cast<char>(h); // 转换为字符并添加到字符串

    // 提取低8位（第2个字节），转换为 ASCII 字符
    uint8_t l = value & 0xFF;         // 掩码获取低8位
    if (l != 0)                       // 只添加非空字符
        _out += static_cast<char>(l); // 转换为字符并添加到字符串

    return _out;
}
/*

 */
int ModbusMaster::_read_FUN_Code(std::vector<EquipProperty> &list)
{
    size_t num = list.size();
    if (num <= 0)
        return -1;

    const uint8_t max_len = 100;
    // 定义足够大的寄存器数组，避免越界
    uint16_t _registers[max_len * 10];
    memset(_registers, 0, sizeof(uint16_t) * max_len * 10);

    // 读取10个寄存器块
    for (int i = 0; i < 10; i++)
    {
        int _offset = i * max_len;
        int rc = modbus_read_registers(ctx,
                                       _offset, // 起始地址
                                       max_len, // 读取数量
                                       _registers + _offset);
        if (rc <= 0)
        {
            ES_LOG(TAG, LEVEL_ERROR, "Fails to modbus_read_registers: (i=%d): %s\n", i, modbus_strerror(errno));
            return -2 - i;
        }

        this_thread::sleep_for(chrono::milliseconds(1)); // 延迟
    }

    //
    for (auto it = list.begin(); it != list.end(); ++it)
    {
        if (it->reg.compare("01") == 0)
        { //Coil Status
        }
        else if (it->reg.compare("02") == 0)
        { //Input Status
        }
        else if (it->reg.compare("03") == 0)
        { //Holding Register
            it->value.clear();

            /**
             * 数据地址来源于配置文件bin\data\dataconfig_modbus.json
             * 使用迭代器正确访问每个数据的地址
             **/
            for (auto it_addr = it->addr.begin(); it_addr != it->addr.end(); ++it_addr)
            {
                // 从迭代器获取当前地址值，而不是固定获取第一个元素
                int addr = *it_addr;

                // 检查地址有效性，避免数组越界
                if (addr < 0 || addr >= max_len * 10)
                {
                    // 可以添加错误处理或跳过无效地址
                    continue;
                }

                //判断数据类型
                if (it->type.compare("float") == 0)
                {
                    // 浮点数通常占用2个寄存器，确保后续地址不越界
                    if (addr + 1 < max_len * 10)
                    {
                        float value = modbus_get_float_abcd(&_registers[addr]);
                        it->value.push_back(std::to_string(value));
                    }
                }
                else if ((it->type.compare("uint16_t") == 0) ||
                         (it->type.compare("short") == 0))
                {
                    it->value.clear();
                    if (it->name_en == "faultcode")
                    { // 假设有一个名为error_code的属性
                        for (auto it_addr = it->addr.begin(); it_addr != it->addr.end(); ++it_addr)
                        {
                            int addr = *it_addr;
                            uint16_t value = _registers[addr];
                            if (addr <= 0 || addr >= max_len * 10)
                            {
                                continue;
                            }

                            string _val = "[" + std::to_string(value) + "]" + getErrorDescription(value);
                            it->value.push_back(_val);

                            // // 获取错误描述并写入（假设需要单独存储描述）
                            // std::string error_desc = getErrorDescription(value);
                            // it->error_description = error_desc; // 需要在EquipProperty中添加该字段
                            // ES_LOG(TAG, LEVEL_INFO, "Detected error: %d - %s", value, error_desc.c_str());
                        }
                    }
                    else
                    {
                        uint16_t value = _registers[addr];
                        it->value.push_back(std::to_string(value));
                    }
                }
                else if ((it->type.compare("uint32_t") == 0) ||
                         (it->type.compare("int") == 0))
                {
                    // 32位整数通常占用2个寄存器，确保后续地址不越界
                    if (addr + 1 < max_len * 10)
                    {
                        // 修正宏的使用方式，获取32位整数
                        uint32_t value = MODBUS_GET_INT32_FROM_INT16(_registers, addr);
                        it->value.push_back(std::to_string(value));
                    }
                }
                else if (it->type.compare("uchar") == 0)
                {
                    string _val;

                    // 1. 计算最大可访问长度（避免超出_registers数组范围）
                    const int max_reg_idx = max_len * 10 - 1;        // _registers最大有效索引（999）
                    int max_accessible_len = max_reg_idx - addr + 1; // 从addr开始最多可访问的长度
                    if (max_accessible_len <= 0)
                    {
                        ES_LOG(TAG, LEVEL_ERROR, "uchar addr %d is out of registers range (max 999)", addr);
                        it->value.push_back(""); // 空值避免后续处理异常
                        continue;
                    }
                    // 2. 实际访问长度取配置的len和最大可访问长度的最小值
                    int actual_len = min(it->len, max_accessible_len);

                    // 3. 循环访问时再次检查索引
                    for (int i = 0; i < actual_len; i++)
                    {
                        int access_idx = addr + i;
                        if (access_idx < 0 || access_idx > max_reg_idx)
                        {
                            ES_LOG(TAG, LEVEL_ERROR, "uchar access index %d out of range (max 999)", access_idx);
                            break; // 跳出循环，避免继续越界
                        }
                        if (_registers[access_idx] != 0)
                        {
                            string _cell = _ASCII2String(_registers[access_idx]);
                            _val.append(_cell);
                        }
                    }
                    it->value.push_back(_val);
                }
            }
        }
        else if (it->reg.compare("04") == 0)
        { //Input Register
        }
    }

    return 0;
}
// 加载错误码配置文件
bool ModbusMaster::loadErrorCodes(const std::string &file_path)
{
    return error_code_loader_.load(file_path);
}

// 根据错误码获取描述
std::string ModbusMaster::getErrorDescription(int error_code) const
{
    return error_code_loader_.get_description(error_code);
}
